// SPDX-License-Identifier: GPL-2.0
/*
 * gpadc_sensor_csp.c - gpadc csp sensor operation
 *
 * Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include "csp_gpadc.h"

#define T_SENSOR_0		0x21
#define T_SENSOR_1		0x22
#define T_SENSOR_2		0x23
#define T_SENSOR_3		0x24
#define T_SENSOR_4		0x25

/* Set temperature sensor sample rate */
void csp_sensor_set_sample_rate(void *base, SENSOR_SAMPLE_RATE sr)
{
	reg_gpadc_tsc_t reg;

	reg.val = READREG32(base + GPADC_TSC_OFF);
	reg.bits.sr = sr;

	WRITEREG32(base + GPADC_TSC_OFF, reg.val);
}

/* Set temperature sensor sample data average enable */
void csp_sensor_set_sda_en(void *base, u32 en)
{
	reg_gpadc_tsc_t reg;

	reg.val = READREG32(base + GPADC_TSC_OFF);
	reg.bits.avge = en;

	WRITEREG32(base + GPADC_TSC_OFF, reg.val);
}

/* Set temperature sensor enable */
void csp_sensor_set_en(void *base, u32 en)
{
	reg_gpadc_tsc_t reg;

	reg.val = READREG32(base + GPADC_TSC_OFF);
	reg.bits.tsen = en;

	WRITEREG32(base + GPADC_TSC_OFF, reg.val);
}

/* Set temperature sensor data, down or up threshold interrupt enable  */
void csp_sensor_set_int_en(void *base, u32 source, u32 en)
{
	reg_gpadc_tsie_t reg;

	reg.val = READREG32(base + GPADC_TSIE_OFF);
	if (en)
		reg.val |= source;
	else
		reg.val &= ~source;

	WRITEREG32(base + GPADC_TSIE_OFF, reg.val);
}

/* Get temperature sensor interrupt pending */
u32 csp_sensor_get_int_pend(void *base, u32 source)
{
	reg_gpadc_tsis_t reg;

	reg.val = READREG32(base + GPADC_TSIS_OFF);
	return reg.val & source;
}

/* Clear temperature sensor interrupt pending status */
void csp_sensor_clr_int_pend(void *base, u32 source)
{
	reg_gpadc_tsic_t reg;

	reg.val = 0;
	reg.val |= source;

	WRITEREG32(base + GPADC_TSIC_OFF, reg.val);
}

#ifdef CONFIG_LOMBO_THERMAL
int csp_get_slope(int id)
{
	int slope = 0;

	slope = 58180;

	return slope;
}

int csp_calibration_offset(int id)
{
	int offset = 0, offset_1 = 0;
	u32 t_senor_id;

	switch (id) {
	case 0:
		t_senor_id = T_SENSOR_0;
		break;
	case 1:
		t_senor_id = T_SENSOR_1;
		break;
	case 2:
		t_senor_id = T_SENSOR_2;
		break;
	case 3:
		t_senor_id = T_SENSOR_3;
		break;
	case 4:
		t_senor_id = T_SENSOR_4;
		break;
	default:
		t_senor_id = T_SENSOR_0;
		break;
	}

	offset = (int)csp_get_efuse_value(t_senor_id);
	if (id != 0) {
		offset_1 = (int)csp_get_efuse_value(T_SENSOR_0);
		offset = (offset_1 & 0xF00) + offset;
		offset_1 = offset - offset_1;
		if (offset_1 > 0x80)
			offset = offset - 0x100;
		else if (offset_1 < -0x80)
			offset = offset + 0x100;
	}
	/* set default calibration value */
	if (offset == 0)
		offset = 360;
	PRT_DBG("value:0x%x, t_senor_id:0x%x", offset, t_senor_id);
	return offset;
}

long csp_sensor_get_temp(int id, void __iomem *base, int slope, int offset)
{
	long temp_uint = 0;
	long long temp = 0;
	u64 value = 0;
	static int warn_cnt[8];

	value = readl(base + GPADC_TS_X_DAT(id));
	if (value == 0) {
		warn_cnt[id]++;
		if (warn_cnt[id] < 2)
			value = 2000;
		if (id != 0)
			value = readl(base + GPADC_TS_X_DAT(0));
		else
			WARN_ON(value == 0);
	}

	temp = 180LL * 1000000 * 1000000 +
			slope * (offset - value) * 1000000 -
			1406835 * value * value;
	temp_uint = (long)div64_s64(temp, 1000LL * 1000000);

	if (temp_uint >= 120000) {
		PRT_WARN("temp:%lld, value:%lld, slope:%d, offset:%d\n",
			temp, value, slope, offset);
		PRT_WARN("sensor_id:%d, addr:%px\n", id,
				base + GPADC_TS_X_DAT(id));
	}

	return temp_uint;
}

#endif  /* CONFIG_LOMBO_THERMAL */

